/**
 * File: NodeArcStatistic.java
 * Created by: mhaimel
 * Created on: Mar 25, 2010
 * CVS:  $Id: NodeArcStatistic.java 1.0 Mar 25, 2010 2:07:06 PM mhaimel Exp $
 */
package uk.ac.ebi.curtain.model.graph.curtain.filter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicReferenceArray;

import uk.ac.ebi.curtain.model.graph.Arc;
import uk.ac.ebi.curtain.model.graph.Node;
import uk.ac.ebi.curtain.model.graph.GraphAccess.TouchEach;
import uk.ac.ebi.curtain.model.graph.curtain.CategoryReadInfo;
import uk.ac.ebi.curtain.model.graph.curtain.ContigInfo;
import uk.ac.ebi.curtain.model.graph.curtain.ReadWrapper;
import uk.ac.ebi.curtain.model.graph.curtain.StatisticSummary;
import uk.ac.ebi.curtain.utils.StatisticHelper;

/**
 * @author mhaimel
 *
 */
public class NodeArcStatistic implements TouchEach<Node<ContigInfo, ReadWrapper>> {

	private AtomicReferenceArray<LinkedBlockingQueue<Integer>> leftSet;
	private AtomicReferenceArray<LinkedBlockingQueue<Integer>> rightSet;
	private AtomicReferenceArray<LinkedBlockingQueue<Node<ContigInfo, ReadWrapper>>> unconnectedArr;
	private LinkedBlockingQueue<Node<ContigInfo, ReadWrapper>> unconnected = new LinkedBlockingQueue<Node<ContigInfo,ReadWrapper>>(); 

	public NodeArcStatistic(Integer categories) {
		this.leftSet = new AtomicReferenceArray<LinkedBlockingQueue<Integer>>(categories);
		this.rightSet = new AtomicReferenceArray<LinkedBlockingQueue<Integer>>(categories);
		this.unconnectedArr = new AtomicReferenceArray<LinkedBlockingQueue<Node<ContigInfo,ReadWrapper>>>(categories);
		for(int i = 0; i < categories; ++i){
			this.leftSet.set(i, new LinkedBlockingQueue<Integer>());
			this.rightSet.set(i, new LinkedBlockingQueue<Integer>());
			this.unconnectedArr.set(i, new LinkedBlockingQueue<Node<ContigInfo,ReadWrapper>>());
		}
	}

	@Override
	public void touch(Node<ContigInfo, ReadWrapper> node) {
		Set<Integer> left = fillSet(leftSet,node.getLeft());
		Set<Integer> right = fillSet(rightSet,node.getRight());
		Set<Integer> total = new HashSet<Integer>();
		total.addAll(left);
		total.addAll(right);
		if(total.isEmpty()){
			this.unconnected.add(node);
		}
		for(int i = 0; i < unconnectedArr.length(); ++i){
			if(!total.contains(i)){
				this.unconnectedArr.get(i).add(node);
			}
		}		
	}
	
	
	public List<Node<ContigInfo,ReadWrapper>> getUnconnectedNodes(){
		return new ArrayList<Node<ContigInfo, ReadWrapper>>(this.unconnected);
	}
	
	public List<Node<ContigInfo,ReadWrapper>> getUnconnectedNodes(Integer cat){
		return new ArrayList<Node<ContigInfo, ReadWrapper>>(this.unconnectedArr.get(cat));
	}
	
	private Set<Integer> fillSet(AtomicReferenceArray<LinkedBlockingQueue<Integer>> set, List<Arc<ContigInfo, ReadWrapper>> arcs){
		if(arcs.isEmpty()){
			return Collections.emptySet();
		}
		int cat = set.length();
		int[] arr = new int[cat];
		Arrays.fill(arr, 0);
		for(Arc<ContigInfo, ReadWrapper> a : arcs){
			for(int i = 0; i < cat; ++i){
				CategoryReadInfo info = a.getValue().getInfo(i);
				if(null != info){
					arr[i] = ++arr[i];
				}
			}
		}
		Set<Integer> dataSet = new HashSet<Integer>(cat);
		for(int i = 0; i < cat; ++i){
			int val = arr[i];
			if(val > 0){
				set.get(i).add(val);
				dataSet.add(i);
			}
		}
		return dataSet;
	}
	
	public StatisticSummary<Integer> getLeftStatistic(int cat) {
		return getStatistic(this.leftSet.get(cat));
	}
	
	public StatisticSummary<Integer> getRightStatistic(int cat) {
		return getStatistic(this.rightSet.get(cat));
	}
	
	private StatisticSummary<Integer> getStatistic(LinkedBlockingQueue<Integer> arr) {
		List<Integer> list = new ArrayList<Integer>(arr);
		Collections.sort(list);
		return StatisticHelper.getStatistic(list);
	}
	
	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		int length = this.leftSet.length();
		boolean nl = false;
		for(int i = 0; i < length; ++i){
			if(nl) {
				sb.append("\n");
				nl = false;
			}
			sb.append(i).append("L) ").append(getLeftStatistic(i)).append("\n");
			sb.append(i).append("R) ").append(getRightStatistic(i));
			nl = true;
		}
		return sb.toString();
	}
	
	public void reset() {
		int length = this.leftSet.length();
		for(int i = 0; i < length; ++i){
			this.leftSet.get(i).clear();
			this.rightSet.get(i).clear();
		}
	}

}
